package com.java.concurrent;

import java.util.concurrent.atomic.AtomicInteger;

public class ConcurrentUtilKnowledge {

    // 以多线程下的count++为例，采用synchronized成本太高，为此可以采用原子变量替代
    //1. AtomicBoolean
    //2. AtomicInteger
    //3. AtomicLong
    //4. AtomicReference 原子引用类型，以原子方式更新复杂类型
    public static class WhatIsAtomic{

        public static class WhatIsAtomicInteger {

//            private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
            private volatile int value; //volatile保证内存的可见性

            public WhatIsAtomicInteger(int value) {
                this.value = value;
            }

            public WhatIsAtomicInteger() {
            }

            public int get() {
                return value;
            }

            public void set(int newValue) {
                this.value = newValue;
            }

//            public final int getAndSet(int newValue); 以原子方式获取旧值并设置新值
//            public final int getAndIncrement(); 以原子方式获取旧值并加1
//            public final int getAndDecrement(); 以原子方式获取旧值并减1

            public final int incrementAndGet() {
                for(;;) {
                    int current = get();
                    int next = current + 1;
                    if(compareAndSet(current, next)) {
                        return next;
                    }
                }
            }

            // AtomicInteger中的方法的实现都依赖于compareAndSet()方法，及比较比设置也称CAS
            // CAS的更新逻辑是乐观的，它假定冲突比较少
            // 使用CAS更新也就是进行冲突检测，如果冲突了则继续尝试，这种方式是非阻塞的，性能高于synchronized的阻塞式
            public final boolean compareAndSet(int expect, int update) {
//               return U.compareAndSetInt(this, VALUE, expectedValue, newValue); //sun.misc.Unsafe及硬件层面的CAS指令
                return true;
            }


        }

        public static class HowToUseAtomicInteger {
            private static AtomicInteger counter = new AtomicInteger(0);
            static class Visitor extends Thread {
                @Override
                public void run() {
                    for (int i = 0; i < 1000; i++) {
                        counter.incrementAndGet();
                    }
                }
            }

            public static void main(String[] args) throws InterruptedException{
                int num = 1000;
                Thread[] threads = new Thread[num];
                for (int i = 0; i < num; i++) {
                    threads[i] = new Visitor();
                    threads[i].start();
                }

                for (int i = 0; i < num; i++) {
                    threads[i].join();
                }
                System.out.println(counter.get());
            }
        }

        // CAS除了可以实现乐观非阻塞算法外，还可以实现悲观阻塞算法，比如锁
        // 实际上Java并发包中所有的阻塞式工具，算法，容器都是基于CAS的
        public static class HowToUseAtomicIntegerMakeLock {

            private AtomicInteger status = new AtomicInteger(0); //0表示未锁定，1表示锁定
            public void lock() { //只有成功将0设为1才退出，实现阻塞效果
                while (!status.compareAndSet(0, 1)) {
                    Thread.yield();
                }
            }

            public void unlock() {
                status.compareAndSet(1, 0);
            }
        }

        // CAS的ABA问题指假设当前值为A,如果一个线程先将A改成B，再将B改成A则CAS操作无法分辨当前的值是否发生过变化
        // 解决办法是使用AtomicStampedReference在修改值的同时附加一个时间戳，只有值和时间戳都相同才进行修改
        // AtomicStampedReference会将值和时间戳组合成一个对象，这样修改的是一个值保证原子操作
        public static class WhatIsABAQuestion {
//            public boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp);
        }
    }
}
